﻿using UnityEngine;

namespace GameToolkit
{
    [CreateAssetMenu(fileName = "InputVectorDescriptor", menuName = "角色控制/矢量输入描述")]
    public class InputVectorDescriptor : InputDescriptor
    {
        [Header("From GameInput")]
        [SerializeField, GameAxis]
        string m_Horizontal;

        [SerializeField, GameAxis]
        string m_Verticle;

        [Header("From Computer")]
        [SerializeField, Range(0.01f, 1f)]
        float m_Threshold = 0.1f;

        GameInput.IAxis mVerticle;
        GameInput.IAxis mHorizontal;

        public override ActorBehaviour.IInputAction Create(bool fromGameInput)
        {
            if (mVerticle == null && mHorizontal == null && fromGameInput)
            {
                mVerticle = string.IsNullOrEmpty(m_Verticle) ? null : GameInput.GetAxis(m_Verticle, true);
                mHorizontal = string.IsNullOrEmpty(m_Horizontal) ? null : GameInput.GetAxis(m_Horizontal, true);
#if UNITY_EDITOR
                if (mVerticle == null && mHorizontal == null)
                    Debug.LogWarning($"The inputs({m_Horizontal},{m_Verticle}) are not exists.", this);
#endif
                return new ActionFromGinput(this);
            }
            else
            {
                return new ActionFromDesc(this);
            }
        }


        class ActionFromGinput : ActorBehaviour.IInputAction<Vector3>
        {
            GameInput.IAxis mHorizontal;
            GameInput.IAxis mVerticle;
            Camera mCam;

            public ActionFromGinput(InputVectorDescriptor desc)
            {
                mVerticle = desc.mVerticle;
                mHorizontal = desc.mHorizontal;
                mCam = Camera.main;
            }

            public bool IsHolding => (mHorizontal != null && mHorizontal.HasButton) || (mVerticle != null && mVerticle.HasButton);

            public Vector3 GetInputValue()
            {
                if(mCam != null)
                {
                    var right = Vector3.ProjectOnPlane(mCam.transform.right, Vector3.up);
                    var forward = Vector3.ProjectOnPlane(mCam.transform.forward, Vector3.up).normalized;
                    return right * (mHorizontal == null ? 0 : mHorizontal.Value) + forward * (mVerticle == null ? 0 : mVerticle.Value);
                }
                else
                {
                    return new Vector3(mHorizontal == null ? 0 : mHorizontal.Value, 0, mVerticle == null ? 0 : mVerticle.Value);
                }
            }
        }

        class ActionFromDesc : IConfigurableInputAction<Vector3>
        {
            InputVectorDescriptor mDesc;
            Vector3 mValue;
            public ActionFromDesc(InputVectorDescriptor desc)
            {
                mDesc = desc;
            }

            public bool IsHolding => mDesc != null && (Mathf.Abs(mValue.x) >= mDesc.m_Threshold || Mathf.Abs(mValue.y) >= mDesc.m_Threshold || Mathf.Abs(mValue.z) >= mDesc.m_Threshold);

            public void SetValue(Vector3 value)
            {
                mValue = value;
            }

            public Vector3 GetInputValue()
            {
                return mValue;
            }
        }
    }
}
